fix(ui): theme-aware charts + heat-pump card auto re-discovery#532
Conversation
The live charts hard-coded dark-theme colors for canvas chrome (axis text, gridlines, both tooltips, the neutral load line), so they went invisible/wrong on a light background. Add a resolver that reads the CSS theme tokens into concrete canvas colors (cached, invalidated on data-theme change) and use it for all chart chrome; saturated series hues are unchanged. heating.js cached heat-pump discovery once and never re-checked (and an empty [] is truthy, so it stuck) — a pump added while the dashboard was open never appeared without a reload. Re-discover on first load and every 5 min. Co-Authored-By: HuggeK <[email protected]>
… + cache-bust The earlier fix only touched app.js, but index.html loads next-app.js — app.js renders only on /legacy.html. So the live dashboard's charts kept their hard-coded dark chrome and stayed dark/invisible in light mode. Mirror the theme resolver (cssColor + cached chartColors) into next-app.js and apply it to all canvas chrome: the power/energy chart (renderChart), both hover tooltips, and the 24h battery+SoC live-history chart — axis text, gridlines, zero/now/hover lines, tooltip bg+border+text, and the neutral Load line. Saturated data-series hues are unchanged. Bump the cache-bust tokens (next-app.js next19->next20, heating.js heat1->heat2) so browsers actually re-fetch the updated next-app.js and the already-shipped heating.js re-discovery fix instead of serving the stale cached copies. Co-Authored-By: HuggeK <[email protected]>
Each row in the per-driver 'all signals' drill-in now shows the signal's source Modbus register id (m.register from the driver detail metrics, supplied by the NIBE driver / emit_metric register plumbing). Signals with no Modbus mapping render '—'. Bumps heating.js cache token heat2->heat3 so browsers pick up the new column. Co-Authored-By: HuggeK <[email protected]>
88cf9f4 to
62c0d4b
Compare
The heat-pump card renders into a bare .card, whose base rule (style.css) sets background:var(--surface). --surface is hard-coded dark in :root and is NOT flipped by html[data-theme=light], so the card stayed dark on a light page while the type-specific cards (.summary-card etc., themed via --ink-raised) went light. Add a scoped next.css rule putting .heating-row .card on the --ink-raised palette, and bump next.css cache token next6->next7. Co-Authored-By: HuggeK <[email protected]>
…tips Replaces the 4-tile card with a grouped layout (Effekt & el · Temperaturer · Ventilation · Drift · Energi). Each tile shows the NIBE sensor designation in parens (BT21, BE1, GP1 …) and an info icon whose hover tooltip explains the term. Adds 'Total effekt nu' (whole-pump draw) distinct from compressor-only power. Bumps heating.js heat3->heat4. Co-Authored-By: HuggeK <[email protected]>
…power-limit tiles Card labels, tooltips and group titles are now English. Priority shows a word (Off / Hot water / Heating / …) instead of the raw code. The per-tile help icon is a '?' circle matching the existing .plan-help-btn style (border, sizing, accent hover) instead of the custom ⓘ. Adds Power limit / Fuse / Max add. heat tiles. heat4->heat5. Co-Authored-By: HuggeK <[email protected]>
Each group (Power & electrical, Temperatures, …) is now a distinct grey sunken sub-card matching the dashboard's in-card box pattern (--ink-sunken + --line border + radius + padding), so the groups read as separate cards under the heat-pump card. heat5->heat6. Co-Authored-By: HuggeK <[email protected]>
…form
The form treated NIBE as an OAuth (apicreds) driver and seeded
{client_id, client_secret}. Distinguish local basic-auth drivers (apicreds +
connection_defaults.port) and seed {host, username, password} instead. The HTTP
fieldset now renders Username + a Certificate fingerprint (tls_pin_sha256) field
for these drivers; password comes from config_secrets. allowed_hosts is
auto-derived from config.host by the backend (port-insensitive), so no manual
allowlist needed. devices.js tabsplit2->tabsplit3.
Co-Authored-By: HuggeK <[email protected]>
Step 2: a 30-day multi-line SVG chart (outdoor BT1 / supply BT2 / return BT3, distinct hues, themed axis) under the tiles. Step 3: an Energy-per-period box (Today / This week / This month / This year, consumed vs produced) computed client-side as counter deltas across calendar boundaries; periods without enough logged history show 'accumulating'. Both fetch via /api/series (needs the generic parseRange added in the nibe branch for 30d/366d windows). heat6->heat7. Co-Authored-By: HuggeK <[email protected]>
Each row in the All-signals detail now carries an always-visible sub-line explaining what the signal is: the curated card-tile description when one exists, otherwise the device's own point title (m.title, newly served by the API). Keeps the 'All signals' button. heat7->heat8. Co-Authored-By: HuggeK <[email protected]>
…fields Card: clicking a ? help icon no longer navigates into the all-signals detail (onGridClick ignores .ftw-hp-i); the native title tooltip explains the metric in place. Devices tab: the local-HTTP Username + cert-fingerprint inputs now use the same render-then-reveal pattern as the battery field, so they appear for apicreds drivers (NIBE) even when the first render beats the async catalog fetch — previously they were dropped. Tokens heat8->heat9, tabsplit3->tabsplit4. Co-Authored-By: HuggeK <[email protected]>
The battery field was relying on the [hidden] attribute, which any author CSS rule on .field-row children can override. Switch to an inline display:none (beats any selector) on both the initial render and the post-catalog toggle, so the NIBE heat-pump (catalog caps: apicreds, no battery) never shows it. Token tabsplit4->tabsplit5. Co-Authored-By: HuggeK <[email protected]>
What this PR does — NIBE heat-pump card + light-mode fixesA full NIBE S-series heat-pump telemetry card on the dashboard, plus light-theme fixes across the live charts. Light/dark theming
Heat-pump card (
Devices tab (
VerificationVerified live on the test Pi: driver healthy (status OK, polling, 963 metrics all carrying titles + register ids), 30-day chart + ~4 days of energy history rendering, devices-tab fixes confirmed in the running container. Depends on #530 (NIBE driver + |
Pairs with the api fix that placeholders a set-but-blanked driver config secret: /api/config now returns the masked placeholder for a saved password, so the badge reads as set. Reworded so a masked secret isn't mistaken for missing. Token tabsplit5->tabsplit6. Co-Authored-By: HuggeK <[email protected]>
The api blanks config.password but exposes a driver-level has_password flag (config.go MaskSecrets). The Secrets badge only checked the blanked config value, so a saved NIBE password showed as unset. Read has_password for the password key. No backend change needed. Token tabsplit6->tabsplit7. Co-Authored-By: HuggeK <[email protected]>
🔗 Paired with #530 (NIBE telemetry driver)Heads-up: the "independent of the heat-pump driver work" line in the description is now outdated — this PR grew a full NIBE heat-pump card that depends on #530:
Best reviewed / merged together with #530. |
The 30-day temp chart had only faint gridlines (and the SVG text it did have was stretched by preserveAspectRatio=none). Render a proper y-axis (°C, top/mid/bottom) and x-axis (dates across the span) as HTML around the SVG so the labels stay crisp. heat9->heat10. Co-Authored-By: HuggeK <[email protected]>
Replace the axis-less sparkline on the card with a dedicated powerChartBlock: 0-based kW y-axis + HH:MM time x-axis, reusing the temp chart's HTML-axis layout. sparkline() is untouched so the ~937 tiny per-signal detail charts stay minimal. heat10->heat11. Co-Authored-By: HuggeK <[email protected]>
The ~937 detail sparklines were unlabelled. Add a compact per-sparkline min/max (its y-scale) beside each, widen the trend column to fit, and note the shared 24h window in a modal subtitle. sparkline() stays shared/minimal. heat11->heat12. Co-Authored-By: HuggeK <[email protected]>
…imestamp Heat-pump card: (1) the 24h power chart now plots Total drawn / Compressor / Internal add. heat (kW, with legend) instead of compressor-only; (2) the temp chart gains an Extract air (BT20) line and BT sensor codes in the legend (Outdoor BT1 / Supply BT2 / Return BT3), plus a 'supply/return = the heating loop (in-floor / radiators)' subtitle; (3) a 'data as of <time>' stamp under the card header showing the latest poll. heat12->heat13. Co-Authored-By: HuggeK <[email protected]>
frahlg
left a comment
There was a problem hiding this comment.
Reviewed theme handling, NIBE dashboard rendering, settings fields, escaping, and request behavior. Added maintainer fixes to cache long-range history, suppress overlapping refreshes, and limit detail sparklines to curated signals instead of issuing ~980 concurrent series requests. All 226 web tests, local verify-all, and GitHub CI are green; #530 is now on master.
Summary
Two dashboard fixes, independent of the heat-pump driver work.
Charts now render in light mode
The canvas-drawn power/energy charts hard-coded dark-theme colors (axis text, gridlines, zero/now/hover lines, both tooltips' bg+border+text, and the neutral "Load" line + legend swatch), so they went invisible/wrong on a light background. Added a small resolver that reads the CSS theme tokens (
--fg,--fg-dim,--fg-muted,--line,--ink-raised,--accent-e) into concrete canvas colors per draw — cached, and re-read whendata-themeflips. Saturated data-series hues are unchanged (they read on both themes).Heat-pump card auto re-discovery
heating.jsran discovery once and cached it forever — and[]is truthy, so a site that discovered before its pump reportedhp_power_wstayed blank until a manual reload. It now re-scans on first load and every 5 min; steady-state polling still only touches already-known heat-pump drivers.Verification
node --checkpasses on both files.🤖 Generated with Claude Code